#ifndef __UDP_SERVER_HPP__
#define _UDP_SERVER_HPP__

#include <iostream>
#include <memory>
#include <cstring>
#include <string>
#include <sys/types.h>          
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <unistd.h>
#include <functional>

#include "Log.hpp"
#include "Common.hpp"
#include "InetAddr.hpp"
#include "ThreadPool.hpp"

using namespace LogModule;
using namespace ThreadPoolModule;

const static uint16_t gdefaultport=8080;
const static std::string gdefaultip="127.0.0.1";//表示本地主机
const static int gsockfd=-1;


using adduser_t = std::function<void (InetAddr &id)>;
using route_t=std::function<void(int sockfd,std::string message)>;
using task_t=std::function<void()>;

class UdpServer
{
public:
    UdpServer(uint16_t port=gdefaultport) 
    :_sockfd(gsockfd),
    _addr(port),
    _isrunning(false)
    {}

    void InitServer()
    {
        //1.创建socket
        _sockfd=::socket(AF_INET,SOCK_DGRAM,0);
        if(_sockfd<0)
        {
            LOG(LogLevel::FATAL)<<"socket:"<<strerror(errno);
            Die(SOCKET_ERR);
        }
        LOG(LogLevel::INFO)<<"socket sucess,sockfd is: "<<_sockfd;

        //2.填充网络信息
        // struct sockaddr_in local;
        // bzero(&local,sizeof(local));
        // local.sin_family=AF_INET;
        // local.sin_port=::htons(_port);
        // //local.sin_addr.s_addr=::inet_addr(_ip.c_str());//string ip->4bytes 2.转换为网络序列 network order
        // local.sin_addr.s_addr=INADDR_ANY;

        //2.1设置进入内核中  bind
        //int n=::bind(_sockfd,CONV(&local),sizeof(local));
        int n=::bind(_sockfd,_addr.NetAddr(),_addr.NetAddrLen());
        if(n<0)
        {
            LOG(LogLevel::FATAL)<<"bind: "<<strerror(errno);
            Die(BIND_ERR);
        }
        LOG(LogLevel::INFO)<<"bind sucess";

    }

    void RegisterService(adduser_t adduser,route_t route)
    {
        _adduser=adduser;
        _route=route;
    }


    void Start()
    {
        _isrunning=true;
        while(true)
        {
            //通过recvfrom接受消息
            char inbuffer[1024];
            struct sockaddr_in peer;
            socklen_t len=sizeof(peer);

            ssize_t n=::recvfrom(_sockfd,inbuffer,sizeof(inbuffer)-1,0,CONV(&peer),&len);
            if(n>0)
            {
                //消息内容和谁转发的
                // uint16_t clientport=::ntohs(peer.sin_port);
                // std::string clientip=::inet_ntoa(peer.sin_addr);

                InetAddr cli(peer);
                inbuffer[n]=0;
                std::string message=inbuffer;

                //新增用户
                _adduser(cli);

                //构建转发任务，推送给线程池，让线程池进行转发
                task_t task=std::bind(UdpServer::_route,_sockfd,message);
                ThreadPool<task_t>::getInstance()->Equeue(task);
                
            }
        }
        _isrunning=false;
    }
    ~UdpServer() 
    {
        if(_sockfd>gsockfd)
            ::close(_sockfd);
    }  
private:
    int _sockfd;
    //uint16_t _port;//服务器对应的端口号
    // std::string _ip;//服务器所对应的ip
    InetAddr _addr;
    bool _isrunning;//服务器的运行状态

    adduser_t _adduser; //新增用户
    route_t _route;//消息路由
};
#endif